package worker

import (
	"context"
	"crontab/common"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"log"
	"time"
)

var (
	G_LogSkin  *LogSkin
)

type LogSkin struct {
	Client *mongo.Client
	Db *mongo.Database
	Collection *mongo.Collection
	JobLogChan chan *common.JobLog
	AutoCommitChan chan *common.LogBatch
}

// 写入Chan
func (l *LogSkin) PushJobLogChan(jobLog *common.JobLog) {
	l.JobLogChan <- jobLog
}

// 消费 JobLogChan
func (l *LogSkin) JobLogLoop() {
	var (
		jobLog *common.JobLog
		logBatch *common.LogBatch
		timmer *time.Timer
		timeOutLogBatch *common.LogBatch
	)
	for {
		select {
		case  jobLog = <-l.JobLogChan:
			// tips: 一条一条插入比较慢
			if logBatch == nil {
				// 第一次写入 -> 初始化
				logBatch = &common.LogBatch{}
			}
			logBatch.Logs = append(logBatch.Logs,jobLog)
			time.AfterFunc(time.Duration(G_Config.LogTimeOutWriteNum)* time.Second, func(logBatch *common.LogBatch) func() {
				return func() {
					//log.Printf("超时写入")
					// 直接写入或者传入通道
					l.AutoCommitChan <- logBatch
					//log.Println("超时通道数量:" + strconv.Itoa(len(l.AutoCommitChan)))
				}
			}(logBatch))

			// 满足多条写入
			if len(logBatch.Logs) >= G_Config.LogLimitWriteNum {
				// 满足写入条数 -> 写入
				timmer.Stop()
				l.Collection.InsertMany(context.TODO(),logBatch.Logs)
				logBatch = nil
			}
		case timeOutLogBatch = <-l.AutoCommitChan:
			// 写入 相等才写入
			if timeOutLogBatch == logBatch {
				_, err := l.Collection.InsertMany(context.TODO(),timeOutLogBatch.Logs)
				if err != nil {
					log.Printf(err.Error())
					return
				}
				logBatch = nil
			}


		}
	}
}

// 初始化mongodb
func InitLogSkin() (err error) {
	var (
		optionsClient *options.ClientOptions
		client *mongo.Client
		db *mongo.Database
		collection *mongo.Collection
		logSkin *LogSkin
	)
	optionsClient = options.Client();
	// mongoDb连接
	client,err = mongo.Connect(
		context.TODO(),
		optionsClient.ApplyURI(G_Config.MongoUri),
		optionsClient.SetConnectTimeout(time.Duration(G_Config.MongoTimeout) * time.Second),
		optionsClient.SetServerSelectionTimeout(time.Duration(G_Config.MongoTimeout) * time.Second),
		)
	if err != nil {
		return
	}
	if err = client.Ping(context.TODO(),nil); err != nil {
		return
	}
	// 选择库
	db = client.Database("cron")
	// 选择表
	collection = db.Collection("log")
	logSkin = &LogSkin{
		Client: client,
		Db:     db,
		Collection: collection,
		JobLogChan:make(chan *common.JobLog,1000),
		AutoCommitChan:make(chan *common.LogBatch,1000),
	}
	G_LogSkin = logSkin

	// 启动协程消费 JobLogChan
	go G_LogSkin.JobLogLoop()
	return
}
